package com.example.springbooteasycode.aop;

import com.example.springbooteasycode.bootsocket.SocketServer;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

import java.lang.management.ManagementFactory;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

@Aspect
@Component
public class LogBAspect {
    // 格式化时间戳
    private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");

    // 关键：@annotation(logB) 要和方法参数 LogB logB 名称一致，用于绑定
    @Around("@annotation(logB)")
    public Object aroundLogB(ProceedingJoinPoint joinPoint, LogB logB) throws Throwable {
        // 1. 准备日志基础信息
        LogInfo logInfo = new LogInfo();
        logInfo.setTimestamp(sdf.format(new Date()));
        logInfo.setLogLevel("INFO");
        logInfo.setProcessId(getProcessId());
        logInfo.setThreadName(Thread.currentThread().getName());
        logInfo.setClassName(joinPoint.getTarget().getClass().getName());
        logInfo.setServerIp(getLocalIp());

        // 2. 获取注解参数
        logInfo.setCommandModule(logB.commandModule());
        logInfo.setSpecificCommand(logB.specificCommand());
        logInfo.setEncryptMachineIp(logB.encryptMachineIp());
        logInfo.setEncryptMachinePort(logB.encryptMachinePort());
        logInfo.setCommandDesc(logB.commandDesc());

        // 3. 获取Socket相关信息
        logInfo.setPort(SocketServer.getServerPort() + ":" + SocketServer.getClientPort());

        // 4. 获取请求信息
        Object[] args = joinPoint.getArgs();
        logInfo.setRequestInfo(args.length > 0 ? Arrays.toString(args) : "无请求数据");

        // 5. 记录交易开始时间
        long startTime = System.currentTimeMillis();
        logInfo.setTradeStartTime(sdf.format(new Date(startTime)));

        try {
            // 执行目标方法
            Object result = joinPoint.proceed();

            // 6. 处理成功响应
            logInfo.setResponseInfo(result != null ? result.toString() : "无响应数据");
            logInfo.setExceptionInfo("");

            return result;
        } catch (Exception e) {
            // 7. 处理异常情况
            logInfo.setResponseInfo("处理失败");
            logInfo.setExceptionInfo(e.getMessage() + Arrays.toString(e.getStackTrace()));
            throw e;
        } finally {
            // 8. 记录交易结束时间并输出日志
            long endTime = System.currentTimeMillis();
            logInfo.setTradeEndTime(sdf.format(new Date(endTime)));

            // 输出格式化日志
            printLog(logInfo);
        }
    }

    // 打印日志
    private void printLog(LogInfo logInfo) {
        // 按照指定格式输出日志
        String logFormat = "-|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s";
        System.out.println(String.format(logFormat,
                logInfo.getTimestamp(),
                logInfo.getLogLevel(),
                logInfo.getProcessId(),
                logInfo.getThreadName(),
                logInfo.getClassName(),
                logInfo.getTradeStartTime(),
                logInfo.getTradeEndTime(),
                logInfo.getServerIp(),
                logInfo.getAppMonitorName(),
                logInfo.getCommandModule(),
                logInfo.getSpecificCommand(),
                logInfo.getPort(),
                logInfo.getResponseInfo(),
                logInfo.getRequestInfo(),
                logInfo.getCommandDesc(),
                logInfo.getEncryptMachineIp() + ":" + logInfo.getEncryptMachinePort(),
                logInfo.getExceptionInfo()));
    }

    // 获取本地IP
    private String getLocalIp() {
        try {
            return InetAddress.getLocalHost().getHostAddress();
        } catch (UnknownHostException e) {
            return "unknown";
        }
    }

    // 获取进程ID
    private String getProcessId() {
        // Java 9+ 可以使用 ProcessHandle.current().pid()
        // 这里兼容旧版本
        return ManagementFactory.getRuntimeMXBean().getName().split("@")[0];
    }

    // 日志信息封装类
    private static class LogInfo {
        private String timestamp;
        private String logLevel;
        private String processId;
        private String threadName;
        private String className;
        private String tradeStartTime;
        private String tradeEndTime;
        private String serverIp;
        private String appMonitorName = "socket-server"; // 应用监控对象名称，可根据实际情况修改
        private String commandModule;
        private String specificCommand;
        private String port;
        private String responseInfo;
        private String requestInfo;
        private String commandDesc;
        private String encryptMachineIp;
        private String encryptMachinePort;
        private String exceptionInfo;

        // Getter和Setter方法
        public String getTimestamp() { return timestamp; }
        public void setTimestamp(String timestamp) { this.timestamp = timestamp; }
        public String getLogLevel() { return logLevel; }
        public void setLogLevel(String logLevel) { this.logLevel = logLevel; }
        public String getProcessId() { return processId; }
        public void setProcessId(String processId) { this.processId = processId; }
        public String getThreadName() { return threadName; }
        public void setThreadName(String threadName) { this.threadName = threadName; }
        public String getClassName() { return className; }
        public void setClassName(String className) { this.className = className; }
        public String getTradeStartTime() { return tradeStartTime; }
        public void setTradeStartTime(String tradeStartTime) { this.tradeStartTime = tradeStartTime; }
        public String getTradeEndTime() { return tradeEndTime; }
        public void setTradeEndTime(String tradeEndTime) { this.tradeEndTime = tradeEndTime; }
        public String getServerIp() { return serverIp; }
        public void setServerIp(String serverIp) { this.serverIp = serverIp; }
        public String getAppMonitorName() { return appMonitorName; }
        public void setAppMonitorName(String appMonitorName) { this.appMonitorName = appMonitorName; }
        public String getCommandModule() { return commandModule; }
        public void setCommandModule(String commandModule) { this.commandModule = commandModule; }
        public String getSpecificCommand() { return specificCommand; }
        public void setSpecificCommand(String specificCommand) { this.specificCommand = specificCommand; }
        public String getPort() { return port; }
        public void setPort(String port) { this.port = port; }
        public String getResponseInfo() { return responseInfo; }
        public void setResponseInfo(String responseInfo) { this.responseInfo = responseInfo; }
        public String getRequestInfo() { return requestInfo; }
        public void setRequestInfo(String requestInfo) { this.requestInfo = requestInfo; }
        public String getCommandDesc() { return commandDesc; }
        public void setCommandDesc(String commandDesc) { this.commandDesc = commandDesc; }
        public String getEncryptMachineIp() { return encryptMachineIp; }
        public void setEncryptMachineIp(String encryptMachineIp) { this.encryptMachineIp = encryptMachineIp; }
        public String getEncryptMachinePort() { return encryptMachinePort; }
        public void setEncryptMachinePort(String encryptMachinePort) { this.encryptMachinePort = encryptMachinePort; }
        public String getExceptionInfo() { return exceptionInfo; }
        public void setExceptionInfo(String exceptionInfo) { this.exceptionInfo = exceptionInfo; }
    }
}

